篇首语:本文由编程笔记#小编为大家整理,主要介绍了ReactReact全家桶ahooks相关的知识,希望对你有一定的参考价值。
ahooks
一套高质量可靠的 React Hooks 库 //引入
npm install --save ahooks
或 yarn add ahooks
//使用
import useRequest from 'ahooks'
useRequest
是一个强大的异步数据管理
的 Hooks,React 项目中的网络请求场景
使用 useRequest就够了
useRequest
通过插件式组织代码,核心代码极其简单,并且可以很方便的扩展出更高级的功能。目前已有能力包括:
useRequest
的第一个参数是一个异步函数,在组件初次加载
时,会自动触发该函数执行
。同时自动管理该异步函数的 loading
, data
, error
等状态。
useRequest
的第二个参数可以为 options.manual = true
,若设置了这个参数,则 useRequest不会默认触发,需要通过run触发
data:service返回的数据
error:service抛出的异常
loading:service是否在执行
run:手动触发useRequest执行,参数会传递给service
params : 当次执行的 service 的参数数组。比如你触发了 run(1, 2, 3,则 params 等于 [1, 2, 3]
//第一个参数service是异步函数
const data, error, loading,run = useRequest(service,
manual: true//若设置了这个参数,则不会默认触发,需要通过run触发
defaulParams:[]//首次默认执行时,传递给 service 的参数
);
useRequest
提供了以下几个生命周期配置项,供你在异步函数的不同阶段做一些处理。
onBefore
:请求之前触发onSuccess
:请求成功触发onError
:请求失败触发onFinally
:请求完成触发
案例
//按需引入antd组件库
import message from 'antd';
import React, useState from 'react';
import useRequest from 'ahooks';
//异步函数
function editUsername(username: string): Promise<void>
return new Promise((resolve, reject) &#61;>
setTimeout(() &#61;>
if (Math.random() > 0.5)
resolve();
else
reject(new Error(&#39;Failed to modify username&#39;));
, 1000);
);
export default () &#61;>
//添加输入框的内容状态
const [state, setState] &#61; useState(&#39;&#39;);
const loading, run &#61; useRequest(editUsername,
//手动触发
manual: true,
//四个声明周期函数
onBefore: (params) &#61;>
message.info(&#96;Start Request: $params[0]&#96;);
,
onSuccess: (result, params) &#61;>
setState(&#39;&#39;);
message.success(&#96;The username was changed to "$params[0]" !&#96;);
,
onError: (error) &#61;>
message.error(error.message);
,
onFinally: (params, result, error) &#61;>
message.info(&#96;Request finish&#96;);
,
);
return (
<div>
<input
//输入框发生改变时,将状态state设置为e.target.value
onChange&#61;(e) &#61;> setState(e.target.value)
//输入框的内容设置为state
value&#61;state
placeholder&#61;"Please enter username"
style&#61; width: 240, marginRight: 16
/>
//手动触发useRequest
<button disabled&#61;loading type&#61;"button" onClick&#61;() &#61;> run(state)>
loading ? &#39;Loading&#39; : &#39;Edit&#39;
</button>
</div>
);
;
API
const
//service是否正在执行
loading: boolean,
//service返回的数据
data?: TData,
//service抛出的异常
error?: Error,
//当次执行的service的参数数组。比如你触发了run(1, 2, 3)&#xff0c;则params等于[1, 2, 3]
params: TParams || [],
//手动触发service执行&#xff0c;参数会传递给service异常自动处理&#xff0c;通过onError反馈
run: (...params: TParams) &#61;> void,
//与run用法一致&#xff0c;但返回的是Promise&#xff0c;需要自行处理异常。
runAsync: (...params: TParams) &#61;> Promise<TData>,
//使用上一次的 params&#xff0c;重新调用 run
refresh: () &#61;> void,
//使用上一次的params&#xff0c;重新调用runAsync
refreshAsync: () &#61;> Promise<TData>,
//直接修改data
mutate: (data?: TData | ((oldData?: TData) &#61;> (TData | undefined))) &#61;> void,
//取消当前正在进行的请求
cancel: () &#61;> void,
&#61; useRequest<TData, TParams>(
//第一个参数为异步函数
service: (...args: TParams) &#61;> Promise<TData>,
//第二个参数
//如果设置为 true&#xff0c;则需要手动调用 run 或 runAsync 触发执行。
manual?: boolean,
//首次默认执行时&#xff0c;传递给service的参数
defaultParams?: TParams,
//service执行前触发
onBefore?: (params: TParams) &#61;> void,
//service resolve时触发
onSuccess?: (data: TData, params: TParams) &#61;> void,
//service reject时触发
onError?: (e: Error, params: TParams) &#61;> void,
//service 执行完成时触发
onFinally?: (params: TParams, data?: TData, e?: Error) &#61;> void,
);
useRequest还有很多功能具体请参照官网
useAntdTable
&#xff1a; 基于 useRequest
实现&#xff0c;封装了 Ant Design UI组件库中Table与Form联动逻辑。
const tableProps, search, loading &#61; useAntdTable(
async ( current: page, pageSize , formData) &#61;>
const data &#61; await getRoleList( page, pageSize, ...formData )
return
//data包含表格数据data和分页数据(page(当前页) pageSize(每页条数) toatl(数据总数) totalPage(页数总数))
...data,
list: data?.data
,
form
)
// tableProps包含 dataSource: data?.data 和 pagination: current: 1, pageSize: 10, total:
第一个参数为异步函数
&#xff0c;它接收两个参数 :分页数据 current, pageSize, sorter, filters
,其中sorter,ilters用于表格分页、分类筛选等功能和表单数据(formData自定义)
函数自动触发前会自动收集表单框中的数据&#xff0c;带入到接口入参中&#xff0c;格式key:value &#xff1b; 返回的数据结构为 total: number, list: Item[]
。第二个参数一般为form(挂载Form实例)
&#xff0c;也可以增加默认参数或refreshDeps&#xff08;参数格式为数组[ ]&#xff09; &#xff0c;refreshDeps 变化&#xff0c;会重置 current 到第一页&#xff0c;并重新发起请求。tableProps
和 search
字段&#xff0c;管理表格和表单。loading
:异步函数(获取数据的过程)是否在执行,执行中为true,执行结束为falseTable 管理
useAntdTable
会自动管理 Table
分页数据&#xff0c;你只需要把返回的 tableProps
传递给 Table
组件就可以了
<Table columns&#61;columns rowKey&#61;"email" ...tableProps />
useAntdTable 如何和表单形成关联关系?
const form &#61;Form.useForm( ) 创建 Form 实例&#xff0c;用于管理所有数据状态
//创建的form实例要给所需Form表单用
<Form form&#61;form ></Form>
useAntdTable的第二个参数挂载form实例
Form 与 Table 联动
useAntdTable
接收 form
实例后&#xff0c;会返回 search 对象&#xff0c;用来处理表单相关事件。
search.type
支持 simple
和 advance
两个表单切换search.changeType
&#xff0c;切换表单类型search.submit
提交表单行为search.reset
重置当前表单初始化数据
useAntdTable
通过 defaultParams
设置初始化值&#xff0c;defaultParams
是一个数组&#xff0c;第一项为分页相关参数&#xff0c;第二项为表单相关数据。如果有第二个值&#xff0c;我们会帮您初始化表单&#xff01;
表单验证
表单提交之前&#xff0c;我们会调用 form.validateFields
来校验表单数据&#xff0c;如果验证不通过&#xff0c;则不会发起请求。
API
useRequest
所有参数和返回结果均适用于 useAntdTable
&#xff0c;此处不再赘述。
type Data &#61; total: number; list: any[] ;
type Params &#61; [ current: number; pageSize: number, filter?: any, sorter?: any , [key: string]: any ];
//useAntdTable会返回tableProps和search字段&#xff0c;用于管理表格和表单
const
...,
//tableProp管理表格 Table组件需要的数据&#xff0c;直接透传给Table组件即可
tableProps:
//数据源
dataSource: any[];
//service是否在执行
loading: boolean;
//表格发生改变执行操作
onChange: (
pagination: any,
filters?: any,
sorter?: any,
) &#61;> void;
//分页数据
pagination:
//当前页
current: number;
//每页显示的数据
pageSize: number;
//总数据
total: number;
;
;
//search管理表单
search:
//当前表单类型
type: &#39;simple&#39; | &#39;advance&#39;;
//切换表单类型
changeType: () &#61;> void;
//提交表单
submit: () &#61;> void;
//重置当前表单
reset: () &#61;> void;
;
&#61; useAntdTable<TData extends Data, TParams extends Params>(
//异步函数
//service接收两个参数&#xff0c;第一个参数为分页数据 current, pageSize, sorter, filters &#xff0c;第二个参数为表单数据。
//service 返回的数据结构为 total: number, list: Item[] 。
service: (...args: TParams) &#61;> Promise<TData>,
...,
//接受的第二个参数
//Form实例
form?: any;
//默认表单类型
defaultType?: &#39;simple&#39; | &#39;advance&#39;;
//默认参数&#xff0c;第一项为分页数据&#xff0c;第二项为表单数据
// defaultParams: [
// current: 2, pageSize: 5 ,
// name: &#39;hello&#39;, email: &#39;abc&#64;gmail.com&#39;, gender: &#39;female&#39;
// ],
defaultParams?: TParams,
//默认分页数量
defaultPageSize?: numbe;
//refreshDeps 变化&#xff0c;会重置 current 到第一页&#xff0c;并重新发起请求。
refreshDeps?: any[];
);
useBoolean
&#xff1a; 优雅的管理 boolean 状态的 Hook。
//state状态值和actions操作集合
//Actions toggle为切换state,set设置state,setTrue设置为true,setFals设置为false
const [ state, toggle, set, setTrue, setFalse ] &#61; useBoolean(
//传入的参数可选项&#xff0c;传入默认的状态值
defaultValue?: boolean
);
持久化 function 的 Hook&#xff0c;理论上&#xff0c;可以使用 useMemoizedFn
完全代替 useCallback。
const memoizedFn &#61; useMemoizedFn(fn);
参数
&#xff1a;fn回调函数&#xff0c;引用地址永远不会变化的回调函数返回值
&#xff1a;memoizedFn缓存版本的回调函数const [name, setName] &#61; useState(&#39;xiaoMing&#39;)
const [age, seAge] &#61; useState(20)
// useCallback
// 在 state 变化时&#xff0c;memoFn 地址会变化
const memoFn &#61; useCallback(() &#61;>
console.log(&#39;name&#39;, name, &#39;age&#39;, age)
, [name, age])
// useMemoizedFn
// memoFn 地址永远不会变化
const memoFn &#61; useMemoizedFn(() &#61;>
console.log(&#39;name&#39;, name, &#39;age&#39;, age)
)
useMemoizedFn的实现
const callbackFn &#61; useCallback(() &#61;>
console.log(&#96;Current count is $count&#96;);
, [count]);
在上面的代码中&#xff0c;callbackFn 的 dep 必须包含 count
&#xff0c;保证它被调用时能输出正确的 count&#xff0c;而不是错误的闭包值。但是这样的话&#xff0c;每次 count 发生变化时&#xff0c;callbackFn 本身的引用会变化&#xff0c;会触发依赖 callbackFn 的 ExpensiveTree 组件 重新render。在 ExpensiveTree 角度来看&#xff0c;其实这是一次多余的 render。
实际上&#xff0c;如果我们找到一种方法解决上面所说的问题&#xff0c;就实现了 useMemoizedFn
这个 hook&#xff0c;我们来看看需要解决的问题有哪些
接下来开始解决这些问题&#xff0c;如下&#xff1a;
function useMemoizedFn(fn)
// 这里可以拿到每次最新的 fn&#xff0c;并把它更新到 ref 中&#xff0c;这可以保证此 ref 能够持有最新的 fn 引用
const latestFn &#61; useRef(fn);
latestFn.current &#61; fn;
// 我们通过这个只初始化一次的 useRef 来构建一个函数调用外壳&#xff0c;保证这个外壳函数的引用不会发生变化
// 并且通过在内部持有最新函数的引用&#xff0c;来保证调用准确性
const memoizedFn &#61; useRef((...args) &#61;>
latestFn.current?.(...args);
);
return memoizedFn.current;
到这里&#xff0c;我们已经实现了 useMemoizedFn
的所有功能&#xff0c;简单来说&#xff0c;这个 hook
做的事情就是实时的维护函数的最新引用&#xff0c;并在适当的时候通过一个包装函数来调用它。
通过 url query 来管理 state 的 Hook。
npm i &#64;ahooksjs/use-url-state -S
该 Hooks 基于 react-router 的 useLocation & useHistory & useNavigate 进行 query 管理&#xff0c;一般获取路由参数使用该hook更加简便
使用该 Hooks 之前&#xff0c;你需要保证
你项目正在使用 react-router 5.x 或 6.x 版本来管理路由
独立安装了 &#64;ahooksjs/use-url-state
import useUrlState from &#39;&#64;ahooksjs/use-url-state&#39;;
const [state, setState] &#61; useUrlState(initialState, options);
举个例子:
向路由组件传递search参数&#xff1a;
路由链接(携带参数)&#xff1a;详情
接收参数:
const search,setSearch &#61;useSearchParams()
const name &#61;search.get(&#39;name&#39;)
const id &#61;search.get(&#39;id&#39;)
使用useUrlState
const [query, setQuery] &#61; useUrlState(props, navigateMode: ‘replace’ );
query就直接可以取出name和id